/*
 * H265RtpUnPacker.cpp
 *
 *  Created on: 2018年4月21日
 *      Author: zhengboyuan
 */

#include "H265RtpUnPacker.h"

namespace av
{

H265RtpUnPacker::H265RtpUnPacker()
{
}

H265RtpUnPacker::~H265RtpUnPacker()
{
}

bool H265RtpUnPacker::open(int mediaType, int codec)
{
	m_format.m_codec = MEDIA_CODEC_HEVC;
	return true;
}

bool H265RtpUnPacker::unpack(RtpPacket& pktIn, MediaPacket& pktOut)
{
	static unsigned char s_startCode[] = { 0, 0, 0, 1};

	uint8_t* data = pktIn.data;
	int length = pktIn.size;

	bool isFU = ((data[0] >> 1) & 49) == 49;
	uint8_t naluType = (data[0] & 0x7E) >> 1;
	bool fullPacket = pktIn.mark;
	bool keyFrame = false;

	if (isFU)
	{
		naluType = data[2] & 0x1F;

		uint8_t hdr[2] = {0, data[1]};
		hdr[0] = (data[0] & 0x81) | ((naluType << 1) & 0x7E);

		unsigned char startBit = data[2]&0x80;
		unsigned char endBit = data[2]&0x40;

		if(startBit)
		{
			m_buffer.clear();
			m_buffer.write(s_startCode, sizeof(s_startCode));
			m_buffer.write(hdr, sizeof(hdr));
		}
		else if (m_buffer.empty())
		{
			m_buffer.clear();
			m_buffer.write(s_startCode, sizeof(s_startCode));
			m_buffer.write(hdr, sizeof(hdr));
		}

		data += 3;
		length -= 3;

		m_buffer.write(data, length);

		if (endBit)
		{
			fullPacket = true;

			naluType = (m_buffer.data()[3 + 1] & 0x7E) >> 1;

			keyFrame = (naluType == 32 || naluType == 33 || naluType == 34
				//|| naluType == 39
				|| naluType == 19 || naluType == 20 || naluType == 21);
		}
	}
	else
	{
		if (m_buffer.empty())
		{
			m_buffer.write(s_startCode, sizeof(s_startCode));
		}
		else
		{
			//size_t len = m_buffer.length();
		}

		m_buffer.write(data, length);
		fullPacket = true;
		keyFrame = (naluType == 32 || naluType == 33 || naluType == 34
			//|| naluType == 39
			|| naluType == 19 || naluType == 20 || naluType == 21);
	}

	if (fullPacket)
	{
		pktOut.copy(m_buffer.data(), m_buffer.length());
		pktOut.set_type(MEDIA_TYPE_VIDEO);
		pktOut.set_dts(pktIn.ts);
		pktOut.set_duration(0);

		if (keyFrame)
		{
			pktOut.set_flags(pktOut.flags | MEDIA_FLAG_KEY);
		}

		m_buffer.clear();
	}

	return fullPacket;
}

void H265RtpUnPacker::close()
{
	//
}

bool H265RtpUnPacker::getFormat(MediaFormat& format)
{
	format = m_format;
	return true;
}


} /* namespace av */
